home *** CD-ROM | disk | FTP | other *** search
/ Internet Info 1994 March / Internet Info CD-ROM (Walnut Creek) (March 1994).iso / networking / ip / ka9q / MNetsrc.hqx / Mac TCP_IP Source v.33 / lapb.c < prev    next >
Text File  |  1989-01-13  |  15KB  |  630 lines

  1. /* Link Access Procedures Balanced (LAPB) - with changes for rational
  2.  * behavior over packet radio
  3.  */
  4. #include "global.h"
  5. #include "mbuf.h"
  6. #include "timer.h"
  7. #include "ax25.h"
  8. #include "lapb.h"
  9.  
  10. /* Process incoming frames */
  11. int
  12. lapb_input(axp,cmdrsp,bp)
  13. struct ax25_cb *axp;        /* Link control structure */
  14. char cmdrsp;            /* Command/response flag */
  15. struct mbuf *bp;        /* Rest of frame, starting with ctl */
  16. {
  17.     int16 ftype();
  18.     void lapbstate();
  19.     char control;
  20.     char class;        /* General class (I/S/U) of frame */
  21.     int16 type;        /* Specific type (I/RR/RNR/etc) of frame */
  22.     char pf;        /* extracted poll/final bit */
  23.     char poll = 0;
  24.     char final = 0;
  25.     int nr;            /* ACK number of incoming frame */
  26.     int ns;            /* Seq number of incoming frame */
  27.     char tmp;
  28.  
  29.     if(bp == NULLBUF || axp == NULLAX25){
  30.         free_p(bp);
  31.         return -1;
  32.     }
  33.  
  34.     /* Extract the various parts of the control field for easy use */
  35.     control = pullchar(&bp);
  36.     type = ftype(control);
  37.     class = type & 0x3;
  38.     pf = control & PF;
  39.     /* Check for polls and finals */
  40.     if(pf){
  41.         switch(cmdrsp){
  42.         case COMMAND:
  43.             poll = YES;
  44.             break;
  45.         case RESPONSE:
  46.             final = YES;
  47.             break;
  48.         }
  49.     }
  50.     /* Extract sequence numbers, if present */
  51.     switch(class){
  52.     case I:
  53.     case I+2:
  54.         ns = (control >> 1) & MMASK;
  55.     case S:    /* Note fall-thru */
  56.         nr = (control >> 5) & MMASK;
  57.         break;
  58.     }
  59.     /* This section follows the SDL diagrams by K3NA fairly closely */
  60.     switch(axp->state){
  61.     case DISCONNECTED:
  62.         switch(type){
  63.         case SABM:    /* Initialize or reset link */
  64.             sendctl(axp,RESPONSE,UA|pf);    /* Always accept */
  65.             clr_ex(axp);
  66.             axp->unack = axp->vr = axp->vs = 0;
  67.             lapbstate(axp,CONNECTED);/* Resets state counters */
  68.             start_timer(&axp->t3);
  69.             break;
  70.         case DM:    /* Ignore to avoid infinite loops */
  71.             break;
  72.         default:    /* All others get DM */
  73.             sendctl(axp,RESPONSE,DM|pf);
  74.             break;
  75.         }
  76.         break;
  77.     case SETUP:
  78.         switch(type){
  79.         case SABM:    /* Simultaneous open */
  80.             sendctl(axp,RESPONSE,UA|pf);
  81.             break;
  82.         case DISC:
  83.             sendctl(axp,RESPONSE,DM|pf);
  84.             break;
  85.         case UA:    /* Connection accepted */
  86.             /* Note: xmit queue not cleared */
  87.             stop_timer(&axp->t1);
  88.             start_timer(&axp->t3);
  89.             axp->unack = axp->vr = axp->vs = 0;
  90.             lapbstate(axp,CONNECTED);
  91.             break;            
  92.         case DM:    /* Connection refused */
  93.             free_q(&axp->txq);
  94.             stop_timer(&axp->t1);
  95.             lapbstate(axp,DISCONNECTED);
  96.             break;
  97.         default:    /* All other frames ignored */
  98.             break;
  99.         }
  100.         break;
  101.     case DISCPENDING:
  102.         switch(type){
  103.         case SABM:
  104.             sendctl(axp,RESPONSE,DM|pf);
  105.             break;
  106.         case DISC:
  107.             sendctl(axp,RESPONSE,UA|pf);
  108.             break;
  109.         case UA:
  110.         case DM:
  111.             stop_timer(&axp->t1);
  112.             lapbstate(axp,DISCONNECTED);
  113.             break;
  114.         default:    /* Respond with DM only to command polls */
  115.             if(poll)
  116.                 sendctl(axp,RESPONSE,DM|pf);
  117.             break;
  118.         }
  119.         break;
  120.     case CONNECTED:
  121.         switch(type){
  122.         case SABM:
  123.             sendctl(axp,RESPONSE,UA|pf);
  124.             clr_ex(axp);
  125.             free_q(&axp->txq);
  126.             stop_timer(&axp->t1);
  127.             start_timer(&axp->t3);
  128.             axp->unack = axp->vr = axp->vs = 0;
  129.             lapbstate(axp,CONNECTED); /* Purge queues */
  130.             break;
  131.         case DISC:
  132.             free_q(&axp->txq);
  133.             sendctl(axp,RESPONSE,UA|pf);
  134.             stop_timer(&axp->t1);
  135.             stop_timer(&axp->t3);
  136.             lapbstate(axp,DISCONNECTED);
  137.             break;
  138. /* This code is cribbed from the NOS version, in order to make a */
  139. /* temporary fix to a pathological looping behavior during connect (dmf) */
  140.         case DM:
  141.             lapbstate(axp,DISCONNECTED);
  142.             break;
  143.         case UA:
  144.             est_link(axp);
  145.             lapbstate(axp,SETUP);    /* Re-establish */    
  146.             break;
  147. /* End of cribbed code (dmf) */            
  148.         case FRMR:
  149.             est_link(axp);
  150.             lapbstate(axp,SETUP);    /* Re-establish link */
  151.             break;
  152.         case RR:
  153.         case RNR:
  154.             axp->remotebusy = (control == RNR) ? YES : NO;
  155.             if(poll)
  156.                 enq_resp(axp);
  157.             ackours(axp,nr);
  158.             break;
  159.         case REJ:
  160.             axp->remotebusy = NO;
  161.             if(poll)
  162.                 enq_resp(axp);
  163.             ackours(axp,nr);
  164.             stop_timer(&axp->t1);
  165.             start_timer(&axp->t3);
  166.             /* This may or may not actually invoke transmission,
  167.              * depending on whether this REJ was caused by
  168.              * our losing his prior ACK.
  169.              */
  170.             inv_rex(axp);
  171.             break;    
  172.         case I:
  173.             ackours(axp,nr); /** == -1) */
  174.             if(len_mbuf(axp->rxq) >= axp->window){
  175.                 /* Too bad he didn't listen to us; he'll
  176.                  * have to resend the frame later. This
  177.                  * drastic action is necessary to avoid
  178.                  * deadlock.
  179.                  */
  180.                 if(poll)
  181.                     sendctl(axp,RESPONSE,RNR|pf);
  182.                 free_p(bp);
  183.                 bp = NULLBUF;
  184.                 break;
  185.             }
  186.             /* Reject or ignore I-frames with receive sequence number errors */
  187.             if(ns != axp->vr){
  188.                 if(axp->proto == V1 || !axp->rejsent){
  189.                     axp->rejsent = YES;
  190.                     sendctl(axp,RESPONSE,REJ | pf);
  191.                 }
  192.                 axp->response = 0;
  193.                 stop_timer(&axp->t2);
  194.                 break;
  195.             }
  196.             axp->rejsent = NO;
  197.             axp->vr = (axp->vr+1) & MMASK;
  198.             tmp = len_mbuf(axp->rxq) >= axp->window ? RNR : RR;
  199.             if(poll){
  200.                 sendctl(axp,RESPONSE,tmp|PF);
  201.             } else {
  202.                 axp->response = tmp;
  203.                 start_timer(&axp->t2);
  204.             }
  205.             procdata(axp,bp);
  206.             bp = NULLBUF;
  207.             break;
  208.         default:    /* All others ignored */
  209.             break;
  210.         }
  211.         break;
  212.     case RECOVERY:
  213.         switch(type){
  214.         case SABM:
  215.             sendctl(axp,RESPONSE,UA|pf);
  216.             clr_ex(axp);
  217.             stop_timer(&axp->t1);
  218.             start_timer(&axp->t3);
  219.             axp->unack = axp->vr = axp->vs = 0;
  220.             lapbstate(axp,CONNECTED); /* Purge queues */
  221.             break;
  222.         case DISC:
  223.             free_q(&axp->txq);
  224.             sendctl(axp,RESPONSE,UA|pf);
  225.             stop_timer(&axp->t1);
  226.             stop_timer(&axp->t3);
  227.             axp->response = UA;
  228.             lapbstate(axp,DISCONNECTED);
  229.             break;
  230. /* This code is cribbed from the NOS version, in order to make a */
  231. /* temporary fix to a pathological looping behavior during connect (dmf) */
  232.         case DM:
  233.             lapbstate(axp,DISCONNECTED);
  234.             break;
  235.         case UA:
  236.             est_link(axp);
  237.             lapbstate(axp,SETUP);    /* Re-establish */    
  238.             break;
  239. /* End of cribbed code (dmf) */            
  240.         case FRMR:
  241.             est_link(axp);
  242.             lapbstate(axp,SETUP);    /* Re-establish link */
  243.             break;
  244.         case RR:
  245.         case RNR:
  246.             axp->remotebusy = (control == RNR) ? YES : NO;
  247.             if(axp->proto == V1 || final){
  248.                 stop_timer(&axp->t1);
  249.                 ackours(axp,nr);
  250.                 if(axp->unack != 0){
  251.                     inv_rex(axp);
  252.                 } else {
  253.                     start_timer(&axp->t3);
  254.                     lapbstate(axp,CONNECTED);
  255.                 }
  256.             } else {
  257.                 if(poll)
  258.                     enq_resp(axp);
  259.                 ackours(axp,nr);
  260.                 /* Keep timer running even if all frames
  261.                  * were acked, since we must see a Final
  262.                  */
  263.                 if(!run_timer(&axp->t1))
  264.                     start_timer(&axp->t1);
  265.             }
  266.             break;
  267.         case REJ:
  268.             axp->remotebusy = NO;
  269.             /* Don't insist on a Final response from the old proto */
  270.             if(axp->proto == V1 || final){
  271.                 stop_timer(&axp->t1);
  272.                 ackours(axp,nr);
  273.                 if(axp->unack != 0){
  274.                     inv_rex(axp);
  275.                 } else {
  276.                     start_timer(&axp->t3);
  277.                     lapbstate(axp,CONNECTED);
  278.                 }
  279.             } else {
  280.                 if(poll)
  281.                     enq_resp(axp);
  282.                 ackours(axp,nr);
  283.                 if(axp->unack != 0){
  284.                     /* This is certain to trigger output */
  285.                     inv_rex(axp);
  286.                 }
  287.                 /* A REJ that acks everything but doesn't
  288.                  * have the F bit set can cause a deadlock.
  289.                  * So make sure the timer is running.
  290.                  */
  291.                 if(!run_timer(&axp->t1))
  292.                     start_timer(&axp->t1);
  293.             }
  294.             break;
  295.         case I:
  296.             ackours(axp,nr); /** == -1) */
  297.             /* Make sure timer is running, since an I frame
  298.              * cannot satisfy a poll
  299.              */
  300.             if(!run_timer(&axp->t1))
  301.                 start_timer(&axp->t1);
  302.             if(len_mbuf(axp->rxq) >= axp->window){
  303.                 /* Too bad he didn't listen to us; he'll
  304.                  * have to resend the frame later. This
  305.                  * drastic action is necessary to avoid
  306.                  * memory deadlock.
  307.                  */
  308.                 sendctl(axp,RESPONSE,RNR | pf);
  309.                 free_p(bp);
  310.                 bp = NULLBUF;
  311.                 break;
  312.             }
  313.             /* Reject or ignore I-frames with receive sequence number errors */
  314.             if(ns != axp->vr){
  315.                 if(axp->proto == V1 || !axp->rejsent){
  316.                     axp->rejsent = YES;
  317.                     sendctl(axp,RESPONSE,REJ | pf);
  318.                 }
  319.                 axp->response = 0;
  320.                 stop_timer(&axp->t2);
  321.                 break;
  322.             }
  323.             axp->rejsent = NO;
  324.             axp->vr = (axp->vr+1) & MMASK;
  325.             tmp = len_mbuf(axp->rxq) >= axp->window ? RNR : RR;
  326.             if(poll){
  327.                 sendctl(axp,RESPONSE,tmp|PF);
  328.             } else {
  329.                 axp->response = tmp;
  330.                 start_timer(&axp->t2);
  331.             }
  332.             procdata(axp,bp);
  333.             bp = NULLBUF;
  334.             break;
  335.         default:
  336.             break;        /* Ignored */
  337.         }
  338.         break;
  339.     case FRAMEREJECT:
  340.         switch(type){
  341.         case SABM:
  342.             sendctl(axp,RESPONSE,UA|pf);
  343.             clr_ex(axp);
  344.             axp->unack = axp->vr = axp->vs = 0;
  345.             stop_timer(&axp->t1);
  346.             start_timer(&axp->t3);
  347.             lapbstate(axp,CONNECTED);
  348.             break;
  349.         case DISC:
  350.             free_q(&axp->txq);
  351.             sendctl(axp,RESPONSE,UA|pf);
  352.             stop_timer(&axp->t1);
  353.             lapbstate(axp,DISCONNECTED);
  354.             break;
  355.         case DM:
  356.             stop_timer(&axp->t1);
  357.             lapbstate(axp,DISCONNECTED);
  358.             break;
  359.         default:
  360.             frmr(axp,0,0);
  361.             break;
  362.         }
  363.         break;
  364.     }
  365.     free_p(bp);    /* In case anything's left */
  366.  
  367.     /* See if we can send some data, perhaps piggybacking an ack.
  368.      * If successful, lapb_output will clear axp->response.
  369.      */
  370.     lapb_output(axp);
  371.  
  372.     /* Empty the trash */
  373.     if(axp->state == DISCONNECTED)
  374.         del_ax25(axp);
  375.     return 0;
  376. }
  377. /* Handle incoming acknowledgements for frames we've sent.
  378.  * Free frames being acknowledged.
  379.  * Return -1 to cause a frame reject if number is bad, 0 otherwise
  380.  */
  381. static int
  382. ackours(axp,n)
  383. struct ax25_cb *axp;
  384. char n;
  385. {    
  386.     struct mbuf *bp;
  387.     int acked = 0;    /* Count of frames acked by this ACK */
  388.     int oldest;    /* Seq number of oldest unacked I-frame */
  389.  
  390.     /* Free up acknowledged frames by purging frames from the I-frame
  391.      * transmit queue. Start at the remote end's last reported V(r)
  392.      * and keep going until we reach the new sequence number.
  393.      * If we try to free a null pointer,
  394.      * then we have a frame reject condition.
  395.      */
  396.     oldest = (axp->vs - axp->unack) & MMASK;
  397.     while(axp->unack != 0 && oldest != n){
  398.         if((bp = dequeue(&axp->txq)) == NULLBUF){
  399.             /* Acking unsent frame */
  400.             return -1;
  401.         }
  402.         free_p(bp);
  403.         axp->unack--;
  404.         acked++;
  405.         axp->retries = 0;
  406.         oldest = (oldest + 1) & MMASK;
  407.     }
  408.     if(axp->unack == 0){
  409.         /* All frames acked, stop timeout */
  410.         stop_timer(&axp->t1);
  411.         start_timer(&axp->t3);
  412.     } else if(acked != 0) { 
  413.         /* Partial ACK; restart timer */
  414.         start_timer(&axp->t1);
  415.     }
  416.     /* If user has set a transmit upcall, indicate how many frames
  417.      * may be queued
  418.      */
  419.     if(acked != 0 && axp->t_upcall != NULLVFP)
  420.         (*axp->t_upcall)(axp,axp->paclen * (axp->maxframe - axp->unack));
  421.  
  422.     return 0;
  423. }
  424.  
  425. /* Establish data link */
  426. est_link(axp)
  427. struct ax25_cb *axp;
  428. {
  429.     clr_ex(axp);
  430.     axp->retries = 0;
  431.     sendctl(axp,COMMAND,SABM|PF);
  432.     stop_timer(&axp->t3);
  433.     start_timer(&axp->t1);
  434. }
  435. /* Clear exception conditions */
  436. clr_ex(axp)
  437. struct ax25_cb *axp;
  438. {
  439.     axp->remotebusy = NO;
  440.     axp->rejsent = NO;
  441.     axp->response = 0;
  442.     stop_timer(&axp->t3);
  443. }
  444. /* Enquiry response */
  445. enq_resp(axp)
  446. struct ax25_cb *axp;
  447. {
  448.     char ctl;
  449.  
  450.     ctl = len_mbuf(axp->rxq) >= axp->window ? RNR|PF : RR|PF;    
  451.     sendctl(axp,RESPONSE,ctl);
  452.     axp->response = 0;
  453.     stop_timer(&axp->t3);
  454. }
  455. /* Invoke retransmission */
  456. inv_rex(axp)
  457. struct ax25_cb *axp;
  458. {
  459.     axp->vs -= axp->unack;
  460.     axp->vs &= MMASK;
  461.     axp->unack = 0;
  462. }
  463. /* Generate Frame Reject (FRMR) response
  464.  * If reason != 0, this is the initial error frame
  465.  * If reason == 0, resend the last error frame
  466.  */
  467. int
  468. frmr(axp,control,reason)
  469. register struct ax25_cb *axp;
  470. char control;
  471. char reason;
  472. {
  473.     struct mbuf *frmrinfo;
  474.     register char *cp;
  475.     void lapbstate();
  476.  
  477.     if(reason != 0){
  478.         cp = axp->frmrinfo;
  479.         *cp++ = control;
  480.         *cp++ =  axp->vr << 5 || axp->vs << 1;
  481.         *cp = reason;
  482.     }
  483.     if((frmrinfo = alloc_mbuf(3)) == NULLBUF)
  484.         return -1;    /* No memory */
  485.     frmrinfo->cnt = 3;
  486.     memcpy(frmrinfo->data,axp->frmrinfo,3);
  487.     return sendframe(axp,RESPONSE,FRMR|(control&PF),frmrinfo);
  488. }
  489.  
  490. /* Send S or U frame to currently connected station */
  491. int
  492. sendctl(axp,cmdrsp,cmd)
  493. struct ax25_cb *axp;
  494. char cmdrsp,cmd;
  495. {
  496.     int16 ftype();
  497.  
  498.     if((ftype(cmd) & 0x3) == S)    /* Insert V(R) if S frame */
  499.         cmd |= (axp->vr << 5);
  500.     return sendframe(axp,cmdrsp,cmd,NULLBUF);
  501. }
  502. /* Start data transmission on link, if possible
  503.  * Return number of frames sent
  504.  */
  505. int
  506. lapb_output(axp)
  507. register struct ax25_cb *axp;
  508. {
  509.     register struct mbuf *bp;
  510.     struct mbuf *tbp;
  511.     char control;
  512.     int sent = 0;
  513.     int i;
  514.  
  515.     if(axp == NULLAX25
  516.      || (axp->state != RECOVERY && axp->state != CONNECTED)
  517.      || axp->remotebusy)
  518.         return 0;
  519.  
  520.     /* Dig into the send queue for the first unsent frame */
  521.     bp = axp->txq;
  522.     for(i = 0; i < axp->unack; i++){
  523.         if(bp == NULLBUF)
  524.             break;    /* Nothing to do */
  525.         bp = bp->anext;
  526.     }
  527.     /* Start at first unsent I-frame, stop when either the
  528.      * number of unacknowledged frames reaches the maxframe limit,
  529.      * or when there are no more frames to send
  530.      */
  531.     while(bp != NULLBUF && axp->unack < axp->maxframe){
  532.         control = I | (axp->vs++ << 1) | (axp->vr << 5);
  533.         axp->vs &= MMASK;
  534.         dup_p(&tbp,bp,0,len_mbuf(bp));
  535.         if(tbp == NULLBUF)
  536.             return sent;    /* Probably out of memory */
  537.         sendframe(axp,COMMAND,control,tbp);
  538.         axp->unack++;
  539.         /* We're implicitly acking any data he's sent, so stop any
  540.          * delayed ack
  541.          */
  542.         axp->response = 0;
  543.         stop_timer(&axp->t2);
  544.         if(!run_timer(&axp->t1)){
  545.             stop_timer(&axp->t3);
  546.             start_timer(&axp->t1);
  547.         }
  548.         sent++;
  549.         bp = bp->anext;
  550.     }
  551.     return sent;
  552. }
  553. /* Set new link state.
  554.  * If the new state is disconnected, also free the link control block.
  555.  */
  556. void
  557. lapbstate(axp,s)
  558. struct ax25_cb *axp;
  559. int s;
  560. {
  561.     int oldstate;
  562.  
  563.     oldstate = axp->state;
  564.     axp->state = s;
  565.     if(s == DISCONNECTED){
  566.         stop_timer(&axp->t1);
  567.         stop_timer(&axp->t2);
  568.         stop_timer(&axp->t3);
  569.         free_q(&axp->txq);
  570.     }
  571.     /* Don't bother the client unless the state is really changing */
  572.     if(oldstate != s && axp->s_upcall != NULLVFP)
  573.         (*axp->s_upcall)(axp,oldstate,s);
  574. }
  575. /* Process a valid incoming I frame */
  576. static
  577. procdata(axp,bp)
  578. struct ax25_cb *axp;
  579. struct mbuf *bp;
  580. {
  581.     char pid;
  582.     int ip_route();
  583.  
  584.     /* Extract level 3 PID */
  585.     if(pullup(&bp,&pid,1) != 1)
  586.         return;    /* No PID */
  587.  
  588.     switch(pid & (PID_FIRST|PID_LAST)){
  589.     case PID_FIRST:
  590.         /* "Shouldn't happen", but flush any accumulated frags */
  591.         free_p(axp->rxasm);
  592.         axp->rxasm = NULLBUF;
  593.     case 0:    /* Note fall-thru */
  594.         /* Beginning or middle of message, just accumulate */
  595.         append(&axp->rxasm,bp);
  596.         return;
  597.     case PID_LAST:
  598.         /* Last frame of multi-frame message; extract it */
  599.         append(&axp->rxasm,bp);
  600.         bp = axp->rxasm;
  601.         axp->rxasm = NULLBUF;
  602.         break;
  603.     case PID_FIRST|PID_LAST:
  604.         /* Do nothing with reassembly queue, allowing single-frame
  605.          * messages to be interspersed with fragments of multi-frame
  606.          * messages
  607.          */
  608.         break;
  609.     }
  610.     /* Last frame in sequence; kick entire message upstairs */
  611.     switch(pid & PID_PID){
  612.     case PID_IP:        /* DoD Internet Protocol */
  613.         ip_route(bp,0);
  614.         break;
  615.     case PID_NO_L3:        /* Enqueue for application */
  616.         append(&axp->rxq,bp);
  617.         if(axp->r_upcall != NULLVFP)
  618.             (*axp->r_upcall)(axp,len_mbuf(axp->rxq));
  619.         break;    
  620.     case PID_NETROM:
  621.         nr_route(bp,axp);
  622.         break;
  623.     default:        /* Note: ARP is invalid here */    
  624.         free_p(bp);
  625.         break;            
  626.     }
  627. }
  628.  
  629.  
  630.